package com.tom.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.tom.constants.UserConstant;
import com.tom.domain.VipRegiestLog;
import com.tom.domain.VipUser;
import com.tom.dto.SMSDto;
import com.tom.exception.GloblException;
import com.tom.mapper.VipRegiestLogMapper;
import com.tom.mapper.VipUserMapper;
import com.tom.service.VerfycodeService;
import com.tom.to.SMSTo;
import com.tom.util.AssertUtil;
import com.tom.util.SendMsg;
import com.tom.util.StrUtils;
import com.tom.util.VerifyCodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.validation.constraints.NotEmpty;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static com.tom.constants.MQConstants.EXCHANGE_NAME_TOPIC;

@Service
@Slf4j
public class VerfycodeServiceImpl implements VerfycodeService {
    @Autowired
    private VipRegiestLogMapper vipRegiestLogMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    @Autowired
    private VipUserMapper vipUserMapper;

    /**
     * 生成图片验证码
     * @param key
     * @return
     */
    @Override
    public String getImgCode(String key) {
        // 判断key非空
        AssertUtil.isNotEmpty(key, "非法请求");
        // 生成随机字符串
        String code = StrUtils.getComplexRandomString(4);
        // 存到redis中
        redisTemplate.opsForValue().set(key, code, 10L, TimeUnit.MINUTES);
        try {
            // 生成base64位的图片字符串，返回到前端
            String baseImg = VerifyCodeUtils.VerifyCode(130, 35, code);
            return baseImg;
        } catch (IOException e) {
            e.printStackTrace();
            throw new GloblException("生成验证码失败");
        }
    }

    /**
     * 生成短信验证码
     * @param dto
     */
    @Override
    public void getSMSCode(SMSDto dto) {
        // 判断参数是否为空
        String imageCode = dto.getImageCode();
        AssertUtil.isNotEmpty(imageCode, "图片验证码不能为空");

        String imageCodeKey = dto.getImageCodeKey();
        AssertUtil.isNotEmpty(imageCodeKey, "非法请求key为空怎么回事小老弟哦");

        String mobile = dto.getMobile();
        AssertUtil.isNotEmpty(mobile, "电话号码不能为空");

        if (dto == null){
            throw new GloblException("参数对象为空");
        }
        // 判断图形验证码是否正确
        if(redisTemplate.opsForValue().get(imageCodeKey) == null){
            throw new GloblException("请重新填写验证码");
        }
        String code = redisTemplate.opsForValue().get(imageCodeKey).toString();
        if (code == null){
            throw new GloblException("请获取图形验证码");
        }

        // 都转换为小写方便比较
        if (!code.toLowerCase().equals(imageCode.toLowerCase())){
            throw new GloblException("图形验证码输入的不正确");
        }

//        // 判断手机号是否已经存在,注册的时候手机号不能重复，绑定的时候手机号重复，只需要将手机号和微信绑定就行
//        EntityWrapper wrapper = new EntityWrapper();
//        wrapper.eq("phone", dto.getMobile());
//        List<VipUser> list = vipUserMapper.selectList(wrapper);
//        if (list.size() != 0){
//            throw new GloblException("该手机号已经被注册过");
//        }
        Object redisVerif = null;
        //  三分钟过期，从redis中取，取到就没有过期, key：业务标识+手机号
        redisVerif = redisTemplate.opsForValue().get(UserConstant.REGISTER_PREFIX + mobile);
        // 事先申明验证码，使得没有找到和未过期从新对验证码生成的时候可以公用
        String codeSMS = null;
        if (redisVerif != null){
            //  判断当前验证码是否超过一分钟，没有超过一分钟，直接抛异常，提示：验证码已经发送，请勿频繁操作
            //   value：时间戳+":"code
            String time = redisVerif.toString().split(":")[0];

            // 判断验证码小于60秒
            if (System.currentTimeMillis()-Long.valueOf(time)<60000){
                throw new GloblException("验证码已经发送，请勿重复操作");
            }else {  //  超过一分钟，重新刷新之前验证码的过期时间，由于该操作和取不到验证码的情况一样就放在最后写
                codeSMS = redisVerif.toString().split(":")[1];
            }
        }else {
            //   如果取不到，重新生成验证码 。由于该操作和刷新验证码的情况一样就放在最后写
            codeSMS = StrUtils.getComplexRandomString(4);
        }
        //   value 3个参数 验证码， 过期时间值， 时间单位
        redisTemplate.opsForValue().set(UserConstant.REGISTER_PREFIX + mobile,
                System.currentTimeMillis() + ":" + codeSMS,
                3L,
                TimeUnit.MINUTES);
        // 使用工具类发送短信
        //SendMsg.sendSMS(mobile, "验证码"+code+"三分钟内填写");
        // System.out.println(redisTemplate.opsForValue().get(UserConstant.BINDER_PREFIX + param.get("phone")));
        // 使用rebbitMQ发送短信
        rabbitTemplate.convertAndSend(EXCHANGE_NAME_TOPIC, "course.sms", new SMSTo(Arrays.asList(mobile),String.format("短信验证码为%s，请在三分钟之内填写",codeSMS)));
        log.info("短信验证码为{}，请在三分钟之内填写", codeSMS);
        // 将发送短信的信息加入到数据库的表中 id 手机号，时间，验证码，key，业务
        VipRegiestLog log = new VipRegiestLog();
        log.setCreateTime(new Date());
        log.setKey(UserConstant.REGISTER_PREFIX+mobile);
        log.setSmsCode(System.currentTimeMillis() + ":" + codeSMS);
        log.setType(1);
        log.setPhone(mobile);
        vipRegiestLogMapper.insert(log);
        // 删除图片验证码
        redisTemplate.delete(imageCodeKey);
    }
}
